package com.chaudcast;

import java.io.IOException;
import java.util.Hashtable;

import javax.microedition.media.Control;
import javax.microedition.media.protocol.ContentDescriptor;
import javax.microedition.media.protocol.DataSource;
import javax.microedition.media.protocol.SourceStream;


public class ShoutcastStream extends DataSource implements SourceStream {
	/* bitrate in kbps */
	private int _bitrate;
	/* current title (icy-name) */
	private String _title;
	/* Location */
	private String _location;
	/* Content-Type */
	private String _contentType;
	/* Genre */
	private String _genre;
	/* Website */
	private String _website;
	/* Meta information interval */
	private int _metaInt;
	
	public ShoutcastStream (String locator) throws IOException {
		super(locator);
		_location = locator;
		String temp;
		temp = Network.open(_location);
		parseMeta(temp);
		System.out.println("Content-type: "+_contentType);
		System.out.println("Bitrate: "+_bitrate);
		Network.setStartBuffer(((_bitrate*1000)/8)*60);
		Network.setPauseBytes(((_bitrate*1000)/8)*30);
		Network.setResumeBytes(((_bitrate*1000)/8)*45);
	}
	
	/* bitrate in kbps */
	public int getBitrate() { return this._bitrate;}
	
	/* get title */
	public String getTitle() { return this._title;}

	/* parse meta information */
	private void parseMeta(String temp) {
		// Hashtable to store meta info 
		Hashtable metaInfo = new Hashtable();
		
		String key, value;
		int startPos = 0;
		int endPos = 0;
		
		// extract values
		startPos = temp.indexOf('\n')+1;
		endPos = temp.indexOf(':',startPos);
		while (startPos != -1 && endPos != -1) {
			key = temp.substring(startPos, endPos).trim();
			startPos = endPos+1;
			endPos = temp.indexOf('\n', startPos);
			value = temp.substring(startPos, endPos).trim();
			startPos = endPos+1;
			endPos = temp.indexOf(':', startPos);
			metaInfo.put(key, value);
		}
		try {
			_title = metaInfo.get("icy-name").toString();
		} catch (NullPointerException npe) {
			// no title
			_title = "";
		}
		try {
			_bitrate = Integer.parseInt(metaInfo.get("icy-br").toString());
		} catch (NumberFormatException nfe) {
			// can't parse bitrate, guess 64
			_bitrate = 64;
		} catch (NullPointerException npe) {
			// no content type
			_bitrate = 64;
		}
		try {
			_contentType = metaInfo.get("content-type").toString();
			// tweak for AAC+
			if (_contentType.equals("audio/aacp")) _contentType = "audio/aac";
		} catch (NullPointerException npe) {
			// no content type
			_contentType = "audio/mpeg";
		}
		try {
			_genre = metaInfo.get("icy-genre").toString();
		} catch (NullPointerException npe) {
			// no genre
			_genre = "";
		}
		try {
			_website = metaInfo.get("icy-url").toString();
		} catch (NullPointerException npe) {
			// no website
			_website = "";
		}
		try {
			_metaInt = Integer.parseInt(metaInfo.get("icy-metaint").toString());
		} catch (NumberFormatException nfe) {
			// no meta interval
			_metaInt = 0;
		} catch (NullPointerException npe) {
			// no meta interval
			_metaInt = 0;
		}
	}
	
	public void connect() throws IOException {

		
	}

	public void disconnect() {
		Network.close();
	}

	public String getContentType() {
		return _contentType;
	}

	public SourceStream[] getStreams() {
		SourceStream[] result = new SourceStream[1];
		result[0] = this;
		return result;
	}

	public void start() throws IOException {
		System.out.println("Starting player...");
		
		//System.out.println(_title);
		Network.load();
	}

	public void stop() throws IOException {
		Network.close();
		
	}

	public Control getControl(String arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	public Control[] getControls() {
		// TODO Auto-generated method stub
		return null;
	}

	public ContentDescriptor getContentDescriptor() {
		return new ContentDescriptor(_contentType);
	}

	/**
     * Returns -1
     * @return long -1
     */
	public long getContentLength() {
		return -1;
	}

    /**
     * Returns the seek type of the stream: NOT_SEEKABLE
     */
	public int getSeekType() {
		return NOT_SEEKABLE;
	}

    /**
     * Returns the maximum size (in bytes) of a single read
     * calculated using the bitrate
     */
	public int getTransferSize() {
		return (_bitrate*1000)/8;
	}

	public int read(byte[] bytes, int off, int len) throws IOException {
    	// ensure we are not asking for too much
    	if (len > getTransferSize()) {
    		len = getTransferSize();
    	}
		return Network.read(bytes, off, len);
	}

	public long seek(long arg0) throws IOException {
		// TODO Auto-generated method stub
		return 0;
	}

	public long tell() {
		// TODO Auto-generated method stub
		return 0;
	}

}
